package com.csaba.connector.otp.parser;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.Currency;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import au.id.jericho.lib.html.Element;
import au.id.jericho.lib.html.HTMLElementName;
import au.id.jericho.lib.html.Source;

import com.csaba.connector.model.Account;
import com.csaba.connector.model.Amount;
import com.csaba.connector.otp.model.OTPBank;
import com.csaba.util.LoggerHelper;

public class AccountBalanceParser
{
	public static final String ACCOUNT_INDEX = "account.index";

	private final static Logger logger = LoggerHelper.getDefaultLogger();

	private static final String INDICATOR_OK = "eredmenytabla";

	@SuppressWarnings( "unchecked" )
	public static Account[] parseAccountList( final Reader reader ) throws IOException, ParseException
	{
		final Source source = new Source(reader);

		// find the account table
		Element table = source.findNextElement(0, "class", "eredmenytabla", false);
		while ( table != null && !table.getStartTag().getName().equals(HTMLElementName.TABLE) )
		{
			table = source.findNextElement(table.getBegin(), "class", "eredmenytabla", false);
		}
		if ( table == null )
			throw new ParseException("Missing result table for account list.", 0);

		// get body
		final Element tbody = (Element) table.findAllElements(HTMLElementName.TBODY).get(0);
		if ( tbody == null )
			throw new ParseException("Unexpected table structure. TBODY is missing.", table.getBegin());
		final List trs = tbody.getChildElements();
		if ( trs == null || trs.size() == 0 )
			return new Account[0];

		final Account[] result = new Account[trs.size()];

		for ( int i = 0; i < trs.size(); i++ )
		{
			final Element tr = (Element) trs.get(i);

			final List fields = tr.getChildElements();
			/*	
			 * <th scope="col">&nbsp;</th> --> account select URI in a <a href>
			 * <th scope="col">Sz�mlasz�m</th>
			 * <th scope="col">Sz�mla elnevez�se</th> 
			 * <th scope="col">Rendelkez�sre �ll� egyenleg</th> 
			 * <th scope="col">Hitelkeret</th> 
			 * <th scope="col">Lek�t�tt bet�tek �sszesen</th>
			 */
			if ( fields.size() < 6 )
			{
				throw new ParseException("Invalid account list structure. Missing columns:" + fields.size(), tr
						.getBegin());
			}
			result[i] = new Account();
			result[i].setBank(OTPBank.getInstance());

			//account index is stored on account list.
			final String accountSelectURI = ( (Element) ( (Element) fields.get(0) ).findAllElements(HTMLElementName.A)
					.get(0) ).getAttributeValue("href");
			result[i].setRemoteProperty(ACCOUNT_INDEX, accountSelectURI.substring(accountSelectURI
					.indexOf("szamlaSzamIndex=")
					+ "szamlaSzamIndex=".length()));

			//parse account fields
			final String accCur = ( (Element) fields.get(1) ).getContent().toString();
			final String accName = ( (Element) fields.get(2) ).getContent().toString().trim();
			final String available = ( (Element) fields.get(3) ).getContent().toString().trim();
			final String overdraft = ( (Element) fields.get(4) ).getContent().toString().trim();
			final String deposits = ( (Element) fields.get(5) ).getContent().toString().trim();

			final StringTokenizer accountParts = new StringTokenizer(accCur, "&-");
			final StringBuffer account = new StringBuffer();

			String currency = accountParts.nextToken().trim();
			do
			{
				if ( currency.length() > 0 )
				{
					if ( account.length() > 0 )
						account.append("-");
					account.append(currency);
				}
				currency = accountParts.nextToken().trim(); // last part will be the currency
			}
			while ( accountParts.hasMoreTokens() );
			if ( currency.startsWith("nbsp;") )
				currency = currency.substring(5);

			final DecimalFormat amountFormat = OTPCodes.amountFormat.get();
			final double availableAmount = amountFormat.parse(available).doubleValue();
			final double overdraftLimit = amountFormat.parse(overdraft).doubleValue();
			final double depositAmount = amountFormat.parse(deposits).doubleValue();

			result[i].setNumber(account.toString());
			result[i].setName(accName);
			result[i].setCurrency(Currency.getInstance(currency));

			result[i].setAvailableBalance(new Amount(availableAmount, result[i].getCurrency()));
			result[i].setBookedBalance(new Amount(availableAmount - overdraftLimit + depositAmount, result[i]
					.getCurrency()));
			result[i].setRemoteProperty("overdraft.limit", new Amount(overdraftLimit, result[i].getCurrency()));
			result[i].setRemoteProperty("term.deposits", new Amount(depositAmount, result[i].getCurrency()));
		}

		return result;
	}

	public static boolean isParsable( final String result )
	{
		return result.contains(INDICATOR_OK);
	}

	/**
	 * @param args
	 * @throws IOException
	 * @throws MalformedURLException
	 * @throws ParseException
	 */
	public static void main( final String[] args ) throws MalformedURLException, IOException, ParseException
	{
		LoggerHelper.initLogger(Level.FINE);

		final FileInputStream fis = new FileInputStream(args[0]);
		final Account[] account = parseAccountList(new InputStreamReader(fis, OTPCodes.HTML_CHARSET));
		for ( final Account acc : account )
		{
			logger.info("acc: " + acc);
		}

	}
}
